﻿using System;
using System.Text;
using Microsoft.Crm.Sdk;
using Microsoft.Crm.Sdk.Query;
using Microsoft.Crm.SdkTypeProxy;
using System.Xml;
using System.Xml.XPath;

using System.Collections.Generic;



namespace CSP.CRM.Deployer
{
  /// <summary>
  /// Creates a custom CSP role and sets its security accesses.
  /// </summary>
  public class RoleDeployer
  {
    private CrmService crm;
    private string crmUserLoginName;

    public RoleDeployer(CrmService crm, string crmUserLoginName)
    {
      this.crm = crm;
      this.crmUserLoginName = crmUserLoginName;
    }

    private systemuser FetchUser()
    {
      QueryByAttribute q = new QueryByAttribute();
      q.EntityName = EntityName.systemuser.ToString();
      q.Attributes = new string[] { "domainname" };
      q.Values = new string[] { crmUserLoginName };
      q.ColumnSet = new AllColumns();


      RetrieveMultipleRequest req = new RetrieveMultipleRequest();
      req.Query = q;
      RetrieveMultipleResponse resp = (RetrieveMultipleResponse)crm.Execute(req);
      if (resp.BusinessEntityCollection.BusinessEntities.Count > 0)
      {
        systemuser user = (systemuser)resp.BusinessEntityCollection.BusinessEntities[0];
        return user;
      }
      else
        return null;
    }

    public void Run()
    {
      systemuser user = FetchUser();
      if (user == null)
        return;

      string fetchXml = @"<fetch mapping='logical'>
        <entity name='privilege'>
          <attribute name='name' />
        </entity>
      </fetch>";
      string result = crm.Fetch(fetchXml);

      List<string> globalPrivileges = new List<string>(new string[] { 
        "prvReadEntity", 
        "prvReadAttribute", 
        "prvReadRelationship" 
      
      });

      List<string> basicPrivileges = new List<string>(new string[] { 
        "prvCreateContact",
        "prvWriteContact",
        "prvReadContact",
        "prvAppendToContact",
        "prvCreateIncident",
        "prvReadIncident",
        "prvWriteIncident",
        "prvAssignIncident",
        "prvAppendIncident",
        "prvAppendToIncident",
        "prvCreateActivity",
        "prvAppendActivity"});

      XmlDocument resultDom = new XmlDocument();
      resultDom.LoadXml(result);

      List<RolePrivilege> privilegesList = new List<RolePrivilege>();
      foreach (XmlNode resultNode in resultDom.SelectNodes("/resultset/result"))
      {
        string privilegeName = resultNode.SelectSingleNode("name").FirstChild.Value;
        if (privilegeName.Contains("Delete"))
          continue;
        if (privilegeName.Contains("csp_") || globalPrivileges.Contains(privilegeName) || basicPrivileges.Contains(privilegeName))
        {
          string privilegeId = resultNode.SelectSingleNode("privilegeid").FirstChild.Value;
          RolePrivilege rolePriv = new RolePrivilege();
          if (basicPrivileges.Contains(privilegeName) || privilegeName.Contains("csp_"))
            rolePriv.Depth = PrivilegeDepth.Basic;
          else
            rolePriv.Depth = PrivilegeDepth.Global;
          rolePriv.PrivilegeId = new Guid(privilegeId);
          privilegesList.Add(rolePriv);
        }
      }

      role cspRole = new role();
      cspRole.name = "CSP Internet Site User";
      cspRole.businessunitid = new Lookup();
      cspRole.businessunitid.type = EntityName.businessunit.ToString();
      cspRole.businessunitid.Value = user.businessunitid.Value;
      Guid roleId = crm.Create(cspRole);

      AddPrivilegesRoleRequest addPrivilegesReq = new AddPrivilegesRoleRequest();
      addPrivilegesReq.RoleId = roleId;
      addPrivilegesReq.Privileges = privilegesList.ToArray();
      AddPrivilegesRoleResponse addPrivilegesResp = (AddPrivilegesRoleResponse)crm.Execute(addPrivilegesReq);

      AssignUserRolesRoleRequest assignCspRoleReq = new AssignUserRolesRoleRequest();
      assignCspRoleReq.UserId = user.systemuserid.Value;
      assignCspRoleReq.RoleIds = new Guid[] { roleId };
      AssignUserRolesRoleResponse assignCspRoleResp = (AssignUserRolesRoleResponse)crm.Execute(assignCspRoleReq);

    }
  }
}